use crate::utils;
use bson::{doc, to_bson, to_document, Document};
use serde::{Deserialize, Serialize};
use serde_json::{Result, Value};
use std::fs;

pub fn json_to_bson(json_str: &str) -> Document {
    let v: Value = serde_json::from_str(json_str).unwrap();
    let doc = to_document(&v).unwrap();
    return doc;
}

pub fn load_jsons_in_directory(dir_name: &str) -> Vec<Document> {
    let mut docs = Vec::new();

    for entry in fs::read_dir(dir_name).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        let json_str = utils::get_file_content(path.to_str().unwrap());
        let doc = json_to_bson(&json_str);
        docs.push(doc);
    }

    return docs;
}

pub fn convert_bson_to_bytes(bson_docs: &[Document]) -> Vec<(Option<u64>, Vec<u8>)> {
    let mut docs = Vec::new();

    for bson_doc in bson_docs {
        let id = match bson_doc.get_i64("doc_id") {
            Ok(value) => Some(value as u64),
            Err(_) => None,
        };
        let mut v: Vec<u8> = Vec::new();
        bson_doc.to_writer(&mut v);
        docs.push((id, v));
    }

    return docs;
}

pub fn prepare_docs_for_insertion(
    id_doc_pairs: &Vec<(Option<u64>, Vec<u8>)>,
) -> Vec<(Option<u64>, &[u8])> {
    let mut id_doc_pairs_prepared = Vec::new();

    for (id, doc) in id_doc_pairs {
        id_doc_pairs_prepared.push((*id, &doc[..]));
    }

    return id_doc_pairs_prepared;
}

pub fn parse_documents(id_bytes_pairs: &Vec<(u64, Vec<u8>)>) -> Vec<(u64, Document)> {
    let mut docs = Vec::new();

    for (id, bs) in id_bytes_pairs {
        let mut reader = std::io::Cursor::new(bs);
        let doc_decoded = Document::from_reader(&mut reader).unwrap();
        docs.push((*id, doc_decoded));
    }

    return docs;
}

#[test]
fn test_bson() {
    println!("Hello, world!");

    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into serde_json::Value.
    let v: Value = serde_json::from_str(data).unwrap();

    // Access parts of the data by indexing with square brackets.
    println!(
        "json: Please call {} at the number {}",
        v["name"], v["phones"][0]
    );

    let doc = json_to_bson(data);
    println!(
        "bson: Please call {} at the number {}",
        doc.get("name").unwrap(),
        doc.get("phones").unwrap().as_array().unwrap()[0]
    );

    let mut v: Vec<u8> = Vec::new();
    doc.to_writer(&mut v);

    let mut reader = std::io::Cursor::new(v.clone());
    let doc_decoded = Document::from_reader(&mut reader).unwrap();

    assert_eq!(doc, doc_decoded);

    println!("Decoded bson: {:?}", doc_decoded);
    let a = doc_decoded.get("age").unwrap();
    println!("{}", a.as_i64().unwrap());
}
